package Concurrency2.Chapter03_CAS_Atomic;

import Concurrency2.Chapter03_CAS_Atomic.beans.Some;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Instruction：对比原子工具类与重量级锁在多线程下的性能差异
 * 对Some中的data进行自增 --> 10个线程
 * <p>
 * 结果证明: 使用原子类的自增比重量级锁执行效率更好. 在生产中优先考虑使用原子类的API
 * <p>
 * Author：@author MaLi
 */
public class T05_Comparison_AtomicAndFatLock {
    private static final Object lock = new Object();
    private static final int TURN = 100000;//10万
    private static final int THREADS_COUNT = 10;
    private static final CountDownLatch latch = new CountDownLatch(10);

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        //fatLock();
        atomic();
        System.out.println("Time wasted: " + (System.currentTimeMillis() - start));
    }

    private static void atomic() {
        AtomicInteger data = new AtomicInteger(0);
        ExecutorService pool = Executors.newFixedThreadPool(10);
        //提交10个任务, 进行自增运算100万次, 每个线程10次
        for (int i = 0; i < THREADS_COUNT; i++) {
            pool.submit(() -> {
                for (int j = 0; j < TURN; j++) {
                    //使用内置自旋的API - 执行效率更好
                    data.incrementAndGet();
                    /*
                    // 使用外置自旋的api - 执行效率一般, 比重量级锁稍微好一点
                    boolean b;
                    do {
                        int expectedValue = data.get();
                        b = data.compareAndSet(expectedValue, expectedValue + 1);
                    }while (!b);*/
                }
                latch.countDown();
            });
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("执行结果: " + data);
        pool.shutdownNow();
    }

    private static void fatLock() {
        Some some = new Some();
        ExecutorService pool = Executors.newFixedThreadPool(10);
        //提交10个任务, 进行自增运算100万次, 每个线程10次
        for (int i = 0; i < THREADS_COUNT; i++) {
            pool.submit(() -> {
                for (int j = 0; j < TURN; j++) {
                    synchronized (lock) {
                        some.setData(some.getData() + 1);
                    }
                }
                latch.countDown();
            });
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("执行结果: " + some.getData());
        pool.shutdownNow();
    }

}
